#!/usr/bin/with-contenv bashio
# vim: ft=bash
# shellcheck shell=bash
# ==============================================================================
# Start sshd service if enabled
# ==============================================================================
CERT_DIR=/data/letsencrypt
WORK_DIR=/data/workdir
PROVIDER_ARGUMENTS=()
ACME_CUSTOM_SERVER_ARGUMENTS=()
KEY_ARGUMENTS=()
EAB_ARGUMENTS=()

EMAIL=$(bashio::config 'email')
DOMAINS=$(bashio::config 'domains')
KEYFILE=$(bashio::config 'keyfile')
CERTFILE=$(bashio::config 'certfile')
CHALLENGE=$(bashio::config 'challenge')
DNS_PROVIDER=$(bashio::config 'dns.provider')
ACME_SERVER=$(bashio::config 'acme_server')
ACME_ROOT_CA=$(bashio::config 'acme_root_ca_cert')
EAB_KID=$(bashio::config 'eab_kid')
EAB_HMAC_KEY=$(bashio::config 'eab_hmac_key')

if [ "${CHALLENGE}" == "dns" ]; then
    bashio::log.info "Selected DNS Provider: ${DNS_PROVIDER}"

    PROPAGATION_SECONDS=60
    if bashio::config.exists 'dns.propagation_seconds'; then
        PROPAGATION_SECONDS="$(bashio::config 'dns.propagation_seconds')"
    fi
    bashio::log.info "Use propagation seconds: ${PROPAGATION_SECONDS}"
else
    bashio::log.info "Selected http verification"
fi

# AWS
if [ "${CHALLENGE}" == "dns" ] && [ "${DNS_PROVIDER}" == "dns-route53" ]; then
    bashio::config.require 'dns.aws_access_key_id'
    bashio::config.require 'dns.aws_secret_access_key'

    AWS_ACCESS_KEY_ID="$(bashio::config 'dns.aws_access_key_id')"
    AWS_SECRET_ACCESS_KEY="$(bashio::config 'dns.aws_secret_access_key')"

    export AWS_ACCESS_KEY_ID
    export AWS_SECRET_ACCESS_KEY
    PROVIDER_ARGUMENTS+=("--${DNS_PROVIDER}")
#Google
elif [ "${CHALLENGE}" == "dns" ] && [ "${DNS_PROVIDER}" == "dns-google" ]; then
    bashio::config.require 'dns.google_creds'
    GOOGLE_CREDS="$(bashio::config 'dns.google_creds')"

    export GOOGLE_CREDS
    if [ -f "/share/${GOOGLE_CREDS}" ]; then
      cp -f "/share/${GOOGLE_CREDS}" "/data/${GOOGLE_CREDS}"
      chmod 600 "/data/${GOOGLE_CREDS}"
    else
      bashio::log.info "Google Credentials File doesnt exists in folder share."
    fi
    PROVIDER_ARGUMENTS+=("--${DNS_PROVIDER}" "--${DNS_PROVIDER}-credentials" "/data/${GOOGLE_CREDS}")
#Namecheap
elif [ "${CHALLENGE}" == "dns" ] && [ "${DNS_PROVIDER}" == "dns-namecheap" ]; then
    bashio::config.require 'dns.namecheap_username'
    bashio::config.require 'dns.namecheap_api_key'
    PROVIDER_ARGUMENTS+=("--authenticator" "${DNS_PROVIDER}" "--${DNS_PROVIDER}-credentials" "/data/dnsapikey" "--${DNS_PROVIDER}-propagation-seconds" "${PROPAGATION_SECONDS}")
    
#mijn.host
elif [ "${CHALLENGE}" == "dns" ] && [ "${DNS_PROVIDER}" == "dns-mijn-host" ]; then
    bashio::config.require 'dns.mijn_host_api_key'
    PROVIDER_ARGUMENTS+=("--authenticator" "${DNS_PROVIDER}" "--${DNS_PROVIDER}-credentials" "/data/dnsapikey" "--${DNS_PROVIDER}-propagation-seconds" "${PROPAGATION_SECONDS}")
    
#Netcup
elif [ "${CHALLENGE}" == "dns" ] && [ "${DNS_PROVIDER}" == "dns-netcup" ]; then
    bashio::config.require 'dns.netcup_customer_id'
    bashio::config.require 'dns.netcup_api_key'
    bashio::config.require 'dns.netcup_api_password'
    PROVIDER_ARGUMENTS+=("--authenticator" "${DNS_PROVIDER}" "--${DNS_PROVIDER}-credentials" "/data/dnsapikey" "--${DNS_PROVIDER}-propagation-seconds" "${PROPAGATION_SECONDS}")

#Simply
elif [ "${CHALLENGE}" == "dns" ] && [ "${DNS_PROVIDER}" == "dns-simply" ]; then
    bashio::config.require 'dns.simply_account_name'
    bashio::config.require 'dns.simply_api_key'
    PROVIDER_ARGUMENTS+=("--authenticator" "${DNS_PROVIDER}" "--${DNS_PROVIDER}-credentials" "/data/dnsapikey" "--${DNS_PROVIDER}-propagation-seconds" "${PROPAGATION_SECONDS}")

#TransIP
elif [ "${CHALLENGE}" == "dns" ] && [ "${DNS_PROVIDER}" == "dns-transip" ]; then
    bashio::config.require.username 'dns.transip_username'
    bashio::config.require 'dns.transip_api_key'
    if (( PROPAGATION_SECONDS < 240 )); then
        bashio::log.info "Increasing DNS propagation limit for TransIP to at least 240 seconds."
        PROPAGATION_SECONDS=240
    fi
    PROVIDER_ARGUMENTS+=("--authenticator" "${DNS_PROVIDER}" "--${DNS_PROVIDER}-credentials" "/data/dnsapikey" "--${DNS_PROVIDER}-propagation-seconds" "${PROPAGATION_SECONDS}")

# CloudFlare
elif [ "${DNS_PROVIDER}" == "dns-cloudflare" ]; then
    if bashio::config.exists 'dns.cloudflare_api_token'; then
        bashio::log.info "Use CloudFlare token"
        echo "dns_cloudflare_api_token = $(bashio::config 'dns.cloudflare_api_token')" >> "/data/dnsapikey"
    else
        bashio::log.warning "Use CloudFlare global key (not recommended!)"
        echo -e "dns_cloudflare_email = $(bashio::config 'dns.cloudflare_email')\n" \
            "dns_cloudflare_api_key = $(bashio::config 'dns.cloudflare_api_key')\n" >> "/data/dnsapikey"
    fi

    PROVIDER_ARGUMENTS+=("--${DNS_PROVIDER}" "--${DNS_PROVIDER}-credentials" "/data/dnsapikey" "--dns-cloudflare-propagation-seconds" "${PROPAGATION_SECONDS}")

# DigitalOcean
elif [ "${CHALLENGE}" == "dns" ] && [ "${DNS_PROVIDER}" == "dns-digitalocean" ]; then
    bashio::config.require 'dns.digitalocean_token'
    PROVIDER_ARGUMENTS+=("--authenticator" "${DNS_PROVIDER}" "--${DNS_PROVIDER}-credentials" "/data/dnsapikey" "--${DNS_PROVIDER}-propagation-seconds" "${PROPAGATION_SECONDS}")

# DirectAdmin
elif [ "${CHALLENGE}" == "dns" ] && [ "${DNS_PROVIDER}" == "dns-directadmin" ]; then
    bashio::config.require 'dns.directadmin_url'
    bashio::config.require 'dns.directadmin_username'
    bashio::config.require 'dns.directadmin_password'
    PROVIDER_ARGUMENTS+=("--authenticator" "${DNS_PROVIDER}" "--${DNS_PROVIDER}-credentials" "/data/dnsapikey" "--${DNS_PROVIDER}-propagation-seconds" "${PROPAGATION_SECONDS}")

#DuckDNS
elif [ "${CHALLENGE}" == "dns" ] && [ "${DNS_PROVIDER}" == "dns-duckdns" ]; then
    bashio::config.require 'dns.duckdns_token'
    PROVIDER_ARGUMENTS+=("--authenticator" "${DNS_PROVIDER}" "--${DNS_PROVIDER}-credentials" "/data/dnsapikey" "--${DNS_PROVIDER}-propagation-seconds" "${PROPAGATION_SECONDS}")

# Dynu
elif [ "${CHALLENGE}" == "dns" ] && [ "${DNS_PROVIDER}" == "dns-dynu" ]; then
    bashio::config.require 'dns.dynu_auth_token'
    PROVIDER_ARGUMENTS+=("--authenticator" "${DNS_PROVIDER}" "--${DNS_PROVIDER}-credentials" "/data/dnsapikey" "--${DNS_PROVIDER}-propagation-seconds" "${PROPAGATION_SECONDS}")

# Gandi
elif [ "${DNS_PROVIDER}" == "dns-gandi" ]; then
    if bashio::config.exists 'dns.gandi_sharing_id'; then
        bashio::log.info "Use Gandi sharing ID"
        echo "dns_gandi_sharing_id = $(bashio::config 'dns.gandi_sharing_id')" >> "/data/dnsapikey"
    fi
    if bashio::config.exists 'dns.gandi_token'; then
        bashio::log.info "Use Gandi gandi_token"
        echo "dns_gandi_token = $(bashio::config 'dns.gandi_token')" >> "/data/dnsapikey"
    fi
    if bashio::config.exists 'dns.gandi_api_key'; then
        bashio::log.info "Use Gandi gandi_api_key"
        echo "dns_gandi_api_key = $(bashio::config 'dns.gandi_api_key')" >> "/data/dnsapikey"
    fi
    PROVIDER_ARGUMENTS+=("--authenticator" "${DNS_PROVIDER}" "--${DNS_PROVIDER}-credentials" "/data/dnsapikey" "--${DNS_PROVIDER}-propagation-seconds" "${PROPAGATION_SECONDS}" )

# GoDaddy
elif [ "${DNS_PROVIDER}" == "dns-godaddy" ]; then
    bashio::config.require 'dns.godaddy_secret'
    bashio::config.require 'dns.godaddy_key'
    PROVIDER_ARGUMENTS+=("--authenticator" "${DNS_PROVIDER}" "--${DNS_PROVIDER}-credentials" "/data/dnsapikey" "--${DNS_PROVIDER}-propagation-seconds" "${PROPAGATION_SECONDS}")

# Hetzner
elif [ "${CHALLENGE}" == "dns" ] && [ "${DNS_PROVIDER}" == "dns-hetzner" ]; then
    bashio::config.require 'dns.hetzner_api_token'
    PROVIDER_ARGUMENTS+=("--authenticator" "dns-hetzner" "--dns-hetzner-credentials" "/data/dnsapikey" "--dns-hetzner-propagation-seconds" "${PROPAGATION_SECONDS}")

# Infomaniak
elif [ "${CHALLENGE}" == "dns" ] && [ "${DNS_PROVIDER}" == "dns-infomaniak" ]; then
    bashio::config.require 'dns.infomaniak_api_token'
    PROVIDER_ARGUMENTS+=("--authenticator" "${DNS_PROVIDER}" "--${DNS_PROVIDER}-credentials" /data/dnsapikey "--${DNS_PROVIDER}-propagation-seconds" "${PROPAGATION_SECONDS}")

# IONOS
elif [ "${CHALLENGE}" == "dns" ] && [ "${DNS_PROVIDER}" == "dns-ionos" ]; then
    bashio::config.require 'dns.ionos_prefix'
    bashio::config.require 'dns.ionos_secret'
    bashio::config.require 'dns.ionos_endpoint'
    PROVIDER_ARGUMENTS+=("--authenticator" "${DNS_PROVIDER}" "--${DNS_PROVIDER}-credentials" "/data/dnsapikey" "--${DNS_PROVIDER}-propagation-seconds" "${PROPAGATION_SECONDS}")

# Joker
elif [ "${CHALLENGE}" == "dns" ] && [ "${DNS_PROVIDER}" == "dns-joker" ]; then
    bashio::config.require 'dns.joker_username'
    bashio::config.require 'dns.joker_password'
    PROVIDER_ARGUMENTS+=("--authenticator" "${DNS_PROVIDER}" "--${DNS_PROVIDER}-credentials" "/data/dnsapikey" "--${DNS_PROVIDER}-propagation-seconds" "${PROPAGATION_SECONDS}")

# Loopia
elif [ "${CHALLENGE}" == "dns" ] && [ "${DNS_PROVIDER}" == "dns-loopia" ]; then
    bashio::config.require 'dns.loopia_user'
    bashio::config.require 'dns.loopia_password'
    if (( PROPAGATION_SECONDS < 900 )); then
        bashio::log.info "Increasing DNS propagation limit for Loopia to at least 900 seconds due to caching issues."
        PROPAGATION_SECONDS=900
    fi
    PROVIDER_ARGUMENTS+=("--authenticator" "${DNS_PROVIDER}" "--${DNS_PROVIDER}-credentials" "/data/dnsapikey" "--${DNS_PROVIDER}-propagation-seconds" "${PROPAGATION_SECONDS}")

# Plesk
elif [ "${CHALLENGE}" == "dns" ] && [ "${DNS_PROVIDER}" == "dns-plesk" ]; then
    bashio::config.require 'dns.plesk_username'
    bashio::config.require 'dns.plesk_password'
    bashio::config.require 'dns.plesk_api_url'
    if (( PROPAGATION_SECONDS < 120 )); then
        bashio::log.info "Increasing DNS propagation limit for Plesk to at least 120 seconds."
        PROPAGATION_SECONDS=120
    fi
    PROVIDER_ARGUMENTS+=("--authenticator" "${DNS_PROVIDER}" "--${DNS_PROVIDER}-credentials" "/data/dnsapikey" "--${DNS_PROVIDER}-propagation-seconds" "${PROPAGATION_SECONDS}")

# Njalla
elif [ "${CHALLENGE}" == "dns" ] && [ "${DNS_PROVIDER}" == "dns-njalla" ]; then
    bashio::config.require 'dns.njalla_token'
    PROVIDER_ARGUMENTS+=("--authenticator" "${DNS_PROVIDER}" "--${DNS_PROVIDER}-credentials" "/data/dnsapikey" "--${DNS_PROVIDER}-propagation-seconds" "${PROPAGATION_SECONDS}")

# rfc2136
elif [ "${CHALLENGE}" == "dns" ] && [ "${DNS_PROVIDER}" == "dns-rfc2136" ]; then
    PROVIDER_ARGUMENTS+=("--${DNS_PROVIDER}" "--${DNS_PROVIDER}-credentials" "/data/dnsapikey" "--dns-rfc2136-propagation-seconds" "${PROPAGATION_SECONDS}")

# Azure
elif [ "${CHALLENGE}" == "dns" ] && [ "${DNS_PROVIDER}" == "dns-azure" ]; then
    bashio::config.require 'dns.azure_config'
    AZURE_CREDS="$(bashio::config 'dns.azure_config')"

    export AZURE_CREDS
    if [ -f "/share/${AZURE_CREDS}" ]; then
      cp -f "/share/${AZURE_CREDS}" "/data/azure_creds"
      chmod 600 "/data/azure_creds"
    else
      bashio::log.info "Azure credentials file doesn't exist in folder share."
    fi
    PROVIDER_ARGUMENTS+=("--authenticator" "${DNS_PROVIDER}" "--${DNS_PROVIDER}-config" "/data/azure_creds")

# INWX
elif [ "${CHALLENGE}" == "dns" ] && [ "${DNS_PROVIDER}" == "dns-inwx" ]; then
    bashio::config.require 'dns.inwx_username'
    bashio::config.require 'dns.inwx_password'
    bashio::config.require 'dns.inwx_shared_secret'
    PROVIDER_ARGUMENTS+=("-v" "--authenticator" "${DNS_PROVIDER}" "--dns-inwx-credentials" "/data/dnsapikey" "--dns-inwx-propagation-seconds" "${PROPAGATION_SECONDS}")

elif [ "${CHALLENGE}" == "dns" ] && [ "${DNS_PROVIDER}" == "dns-desec" ]; then
    bashio::config.require 'dns.desec_token'
    PROVIDER_ARGUMENTS+=("--authenticator" "${DNS_PROVIDER}" "--${DNS_PROVIDER}-credentials" "/data/dnsapikey" "--${DNS_PROVIDER}-propagation-seconds" "${PROPAGATION_SECONDS}")

#Porkbun
elif  [ "${CHALLENGE}" == "dns" ] && [ "${DNS_PROVIDER}" == "dns-porkbun" ]; then
    bashio::config.require 'dns.porkbun_key'
    bashio::config.require 'dns.porkbun_secret'
    PROVIDER_ARGUMENTS+=("--authenticator" "${DNS_PROVIDER}" "--${DNS_PROVIDER}-credentials" "/data/dnsapikey" "--${DNS_PROVIDER}-propagation-seconds" "${PROPAGATION_SECONDS}")

# ClouDNS
elif [ "${CHALLENGE}" == "dns" ] && [ "${DNS_PROVIDER}" == "dns-cloudns" ]; then
    bashio::config.require 'dns.cloudns_auth_password'
    PROVIDER_ARGUMENTS+=("--authenticator" "${DNS_PROVIDER}" "--${DNS_PROVIDER}-credentials" "/data/dnsapikey" "--${DNS_PROVIDER}-propagation-seconds" "${PROPAGATION_SECONDS}")

# Dreamhost
elif [ "${CHALLENGE}" == "dns" ] && [ "${DNS_PROVIDER}" == "dns-dreamhost" ]; then
    bashio::config.require 'dns.dreamhost_baseurl'
    bashio::config.require 'dns.dreamhost_api_key'
    PROVIDER_ARGUMENTS+=("--authenticator" "${DNS_PROVIDER}" "--dns-dreamhost-credentials" "/data/dnsapikey")

# Hurricane Electric
elif [ "${CHALLENGE}" == "dns" ] && [ "${DNS_PROVIDER}" == "dns-he" ]; then
    bashio::config.require 'dns.he_user'
    bashio::config.require 'dns.he_pass'
    PROVIDER_ARGUMENTS+=("--authenticator" "${DNS_PROVIDER}" "--${DNS_PROVIDER}-credentials" "/data/dnsapikey" "--${DNS_PROVIDER}-propagation-seconds" "${PROPAGATION_SECONDS}")

# easyDNS
elif [ "${CHALLENGE}" == "dns" ] && [ "${DNS_PROVIDER}" == "dns-easydns" ]; then
    bashio::config.require 'dns.easydns_key'
    bashio::config.require 'dns.easydns_token'
    bashio::config.require 'dns.easydns_endpoint'
    PROVIDER_ARGUMENTS+=("--authenticator" "${DNS_PROVIDER}" "--${DNS_PROVIDER}-credentials" "/data/dnsapikey" "--${DNS_PROVIDER}-propagation-seconds" "${PROPAGATION_SECONDS}")

# domainoffensive
elif [ "${CHALLENGE}" == "dns" ] && [ "${DNS_PROVIDER}" == "dns-domainoffensive" ]; then
    bashio::config.require 'dns.domainoffensive_token'
    PROVIDER_ARGUMENTS+=("--authenticator" "${DNS_PROVIDER}" "--${DNS_PROVIDER}-credentials" "/data/dnsapikey" "--agree-tos" "-m ${EMAIL}")

# WebSupport
elif [ "${CHALLENGE}" == "dns" ] && [ "${DNS_PROVIDER}" == "dns-websupport" ]; then
    bashio::config.require 'dns.websupport_identifier'
    bashio::config.require 'dns.websupport_secret_key'
    PROVIDER_ARGUMENTS+=("--authenticator" "${DNS_PROVIDER}" "--${DNS_PROVIDER}-credentials" "/data/dnsapikey" "--${DNS_PROVIDER}-propagation-seconds" "${PROPAGATION_SECONDS}")

# noris network
elif [ "${CHALLENGE}" == "dns" ] && [ "${DNS_PROVIDER}" == "dns-noris" ]; then
    bashio::config.require 'dns.noris_token'
    PROVIDER_ARGUMENTS+=("--authenticator" "${DNS_PROVIDER}" "--${DNS_PROVIDER}-credentials" "/data/dnsapikey" "--${DNS_PROVIDER}-propagation-seconds" "${PROPAGATION_SECONDS}")

#All others
else
    PROVIDER_ARGUMENTS+=("--${DNS_PROVIDER}" "--${DNS_PROVIDER}-credentials" "/data/dnsapikey")
fi

if bashio::config.has_value 'acme_server' ; then
    ACME_CUSTOM_SERVER_ARGUMENTS+=("--server" "${ACME_SERVER}")

    if bashio::config.has_value 'acme_root_ca_cert'; then
      echo "${ACME_ROOT_CA}" > /tmp/root-ca-cert.crt
      # Certbot will automatically open the filepath contained in REQUESTS_CA_BUNDLE for extra CA cert
      export REQUESTS_CA_BUNDLE=/tmp/root-ca-cert.crt
    fi
fi

# Gather all domains into a plaintext file
DOMAIN_ARR=()
for line in $DOMAINS; do
    DOMAIN_ARR+=(-d "$line")
done
echo "$DOMAINS" > /data/domains.gen

# Key detection or manual ECDSA/RSA selection
if bashio::config.exists 'key_type'; then
    # Use key type set in configuration
    KEY_TYPE=$(bashio::config 'key_type')
    KEY_ARGUMENTS+=("--key-type" "${KEY_TYPE}")
    if [ "${KEY_TYPE}" == "ecdsa" ]; then
        if bashio::config.exists 'elliptic_curve'; then
            ELLIPTIC_CURVE=$(bashio::config 'elliptic_curve')
            KEY_ARGUMENTS+=("--elliptic-curve" "${ELLIPTIC_CURVE}")
        else
            KEY_ARGUMENTS+=("--elliptic-curve" "secp384r1")
        fi
    fi
else
    bashio::log.info "Detecting existing certificate type for ${DOMAIN_ARR[1]}"
    readarray -t CBCERTS < <(certbot certificates --non-interactive --cert-name "${DOMAIN_ARR[1]}" --config-dir "$CERT_DIR" --work-dir "$WORK_DIR") 
    for output in "${CBCERTS[@]}"; do
        # shellcheck disable=SC2076
        if [[ $output =~ "No certificates found." ]]; then
            bashio::log.info "No certificate found - using 'ecdsa' key type."
            KEY_ARGUMENTS+=("--key-type" "ecdsa")
            break
        fi
        if [[ $output =~ "Key Type: RSA" ]]; then
            bashio::log.info "Existing certificate using 'rsa' key type."
            KEY_ARGUMENTS+=("--key-type" "rsa")
            break
        fi
        if [[ $output =~ "Key Type: ECDSA" ]]; then
            bashio::log.info "Existing certificate using 'ecdsa' key type."
            KEY_ARGUMENTS+=("--key-type" "ecdsa")
            break
        fi
    done
fi

# Set External Account Binding
if bashio::config.has_value 'eab_kid' ; then
    bashio::config.require 'eab_hmac_key'
    EAB_ARGUMENTS+=("--eab-kid" "${EAB_KID}" "--eab-hmac-key" "${EAB_HMAC_KEY}")
fi

# Generate a new certificate if necessary or expand a previous certificate if domains has changed
if [ "$CHALLENGE" == "dns" ]; then
    certbot certonly --non-interactive --keep-until-expiring --expand \
        --email "$EMAIL" --agree-tos \
        "${KEY_ARGUMENTS[@]}" \
        --cert-name "${DOMAIN_ARR[1]}" "${DOMAIN_ARR[@]}" \
        --config-dir "$CERT_DIR" --work-dir "$WORK_DIR" \
        --preferred-challenges "$CHALLENGE" "${PROVIDER_ARGUMENTS[@]}" \
        --preferred-chain "ISRG Root X1" \
        "${EAB_ARGUMENTS[@]}"
else
    certbot certonly --non-interactive --keep-until-expiring --expand \
        --email "$EMAIL" --agree-tos \
        "${KEY_ARGUMENTS[@]}" \
        --cert-name "${DOMAIN_ARR[1]}" "${DOMAIN_ARR[@]}" \
        --config-dir "$CERT_DIR" --work-dir "$WORK_DIR" \
        --preferred-challenges "$CHALLENGE" "${ACME_CUSTOM_SERVER_ARGUMENTS[@]}" --standalone \
        --preferred-chain "ISRG Root X1" \
        "${EAB_ARGUMENTS[@]}"
fi

# Get the last modified cert directory and copy the cert and private key to store
# shellcheck disable=SC2012
CERT_DIR_LATEST="$(ls -td $CERT_DIR/live/*/ | head -1)"
cp "${CERT_DIR_LATEST}privkey.pem" "/ssl/$KEYFILE"
cp "${CERT_DIR_LATEST}fullchain.pem" "/ssl/$CERTFILE"
